package com.bytesizedhosting.api.android.darthcrap.api;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.bytesizedhosting.api.android.darthcrap.NullArgumentException;

public final class APIData implements Serializable {
	public static final class NewsItem implements Serializable {
		private String strTitle;
		private String strBody;
		private String strAuthor;
		
		public NewsItem(String strTitle, String strBody, String strAuthor) {
			NullArgumentException.testArguments(strTitle,strBody,strAuthor);
			this.strTitle = strTitle.trim();
			this.strBody = strBody.trim();
			this.strAuthor = strAuthor.trim();
		}
		
		public String getTitle() {
			return this.strTitle;
		}
		
		public String getBody() {
			return this.strBody;
		}
		
		public String getAuthor() {
			return this.strAuthor;
		}
		
		private static final long serialVersionUID = 4346606546116966776L;
	}
	
	public static final class Account implements Serializable {
		private String strServerName;
		private	double dblCachedQuota;
		private double dblPercentageQuota;
		private String strLiveQuota;
		private double dblCalculatedQuotaUsage;
		private double dblCalculatedQuotaSoftLimit;
		private double dblCalculatedQuotaHardLimit;
		private double dblCalculatedQuotaPercentage;
		private int intSoftQuota;
		private int intHardQuota;
		private int intDaysTillDeletion;
		private Date datPaidTill;
		private String strWebVNCLink;
		private String strWebUILink;
		private boolean boolUpgradeAvailable;
		private boolean boolIsCached;
		private int intClientID;
		
		private static final Pattern objPattern = Pattern.compile("([0-9]+(?:\\.[0-9]+)?)GB / ([0-9]+(?:\\.[0-9]+)?)GB(?:\\s\\(cached\\))?");
		private static final SimpleDateFormat objDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		
		public Account(String strServerName, String strCachedQuota, String strPercentageQuota, String strLiveQuota, String strSoftQuota, String strHardQuota, String strDaysTillDeltion, String strPaidTillDate, String strWebVNCLink, String strWebUILink, String strUpgradeAvailable, String strClientID) throws ParseException{
			NullArgumentException.testArguments(strServerName, strCachedQuota, strPercentageQuota, strLiveQuota, strSoftQuota, strHardQuota, strDaysTillDeltion, strPaidTillDate, strWebVNCLink, strUpgradeAvailable);
			this.strServerName = strServerName.trim();
			strCachedQuota = strCachedQuota.trim();
			this.dblCachedQuota = Double.parseDouble(strCachedQuota);
			this.strLiveQuota = strLiveQuota.toLowerCase().trim();
			
			boolIsCached = strLiveQuota.contains("cached");
			Matcher objMatcher = objPattern.matcher(strLiveQuota.trim());
			if (!objMatcher.matches()) {
				throw new IllegalArgumentException("Live quota string does not match expected format - " + strLiveQuota.trim());
			}
			else {
				String strCalculatedQuotaUsage = objMatcher.group(1);
				String strCalculatedQuotaLimit = objMatcher.group(2);
				if (strCachedQuota.length() > strCalculatedQuotaUsage.length()) {
					if (strCachedQuota.substring(0,strCalculatedQuotaUsage.length()).equals(strCalculatedQuotaUsage)) {
						strCalculatedQuotaUsage = strCachedQuota;
					}
				}
				this.dblCalculatedQuotaUsage = Double.parseDouble(strCalculatedQuotaUsage);
				this.dblCalculatedQuotaSoftLimit = Double.parseDouble(strCalculatedQuotaLimit); 
			}
			this.intSoftQuota = (int) Double.parseDouble(strSoftQuota.trim());
			this.intHardQuota = (int) Double.parseDouble(strHardQuota.trim());
			this.dblCalculatedQuotaHardLimit = intHardQuota;
			this.intDaysTillDeletion = Integer.parseInt(strDaysTillDeltion.trim());
			Date datPaidTillLocal = null;
			try {
				datPaidTillLocal = objDateFormat.parse(strPaidTillDate.trim());
			}
			catch (ParseException objException) {
				datPaidTillLocal = null;
			}
			this.datPaidTill = datPaidTillLocal;
			this.strWebVNCLink = strWebVNCLink.trim();
			this.strWebUILink = strWebUILink.trim();
			this.boolUpgradeAvailable = Boolean.parseBoolean(strUpgradeAvailable.trim().toLowerCase());
			this.dblCalculatedQuotaPercentage = (this.dblCalculatedQuotaUsage / this.dblCalculatedQuotaSoftLimit)*100;
			if (this.boolIsCached) {
				this.dblPercentageQuota = this.dblCalculatedQuotaPercentage;
			}
			else {
				this.dblPercentageQuota = Double.parseDouble(strPercentageQuota.trim());
			}
			this.intClientID = Integer.parseInt(strClientID);
		}
		
		public String getServerName() {
			return this.strServerName;
		}

		public double getCachedQuota() {
			return this.dblCachedQuota;
		}

		public double getPercentageQuota() {
			return this.dblPercentageQuota;
		}

		public String getLiveQuotaString() {
			return this.strLiveQuota;
		}

		public double getCalculatedQuotaUsage() {
			return this.dblCalculatedQuotaUsage;
		}

		public double getCalculatedQuotaSoftLimit() {
			return this.dblCalculatedQuotaSoftLimit;
		}
		
		public double getCalculatedQuotaHardLimit() {
			return this.dblCalculatedQuotaHardLimit;
		}
		
		public double getCalculatedQuotaPercentage() {
			return this.dblCalculatedQuotaPercentage;
		}

		public int getSoftQuota() {
			return this.intSoftQuota;
		}

		public int getHardQuota() {
			return this.intHardQuota;
		}

		public int getDaysTillDeletion() {
			return this.intDaysTillDeletion;
		}

		public Date getPaidTillDate() {
			// CAN RETURN NULL
			return this.datPaidTill;
		}

		public String getWebVNCLink() {
			return this.strWebVNCLink;
		}

		public String getWebUILink() {
			return this.strWebUILink;
		}

		public boolean isUpgradeAvailable() {
			return this.boolUpgradeAvailable;
		}
		
		public boolean isCached() {
			return this.boolIsCached;
		}
		
		public int getClientID() {
			return this.intClientID;
		}
		
		public String getClientName() {
			switch (this.intClientID) {
				case 0:
					return "Deluge";
				case 1:
					return "µTorrent";
				case 2:
					return "rTorrent";
				default:
					return "(Unknown)";
			}
		}
		
		private static final long serialVersionUID = -3213611547425012097L;
	}
	
	private String strLogin;
	private double dblBalance;
	private ArrayList<NewsItem> lstNewsItems;
	private ArrayList<Account> lstAccounts;
	private Date datLastModifiedTime = new Date();
	
	public APIData(String strLogin, String strBalance) {
		NullArgumentException.testArguments(strLogin,strBalance);
		this.strLogin = strLogin.trim();
		this.dblBalance = Double.parseDouble(strBalance.trim());
		this.lstNewsItems = new ArrayList<NewsItem>();
		this.lstAccounts = new ArrayList<Account>();
		updateLM();
	}
	
	public void addNewsItem(NewsItem objNewsItem) {
		NullArgumentException.testArguments(objNewsItem);
		this.lstNewsItems.add(objNewsItem);
		updateLM();
	}
	
	public void addAccount(Account objAccount) {
		NullArgumentException.testArguments(objAccount);
		this.lstAccounts.add(objAccount);
		updateLM();
	}
	
	private void updateLM() {
		this.datLastModifiedTime = new Date();
	}
	
	public String getLogin() {
		return this.strLogin;
	}
	
	public double getBalance() {
		return this.dblBalance;
	}
	
	public Date getLastModifiedTime() {
		return this.datLastModifiedTime;
	}
	
	public Iterable<NewsItem> getNewsItemIterator() {
		return new Iterable<NewsItem>() {
			public Iterator<NewsItem> iterator() {
				return Collections.unmodifiableList(lstNewsItems).iterator();
			}
		};
	}
	
	public Iterable<Account> getAccountIterator() {
		return new Iterable<Account>() {
			public Iterator<Account> iterator() {
				return Collections.unmodifiableList(lstAccounts).iterator();
			}
		};
	}
	
	public int getAccountCount() {
		return this.lstAccounts.size();
	}
	
	public int getNewsItemCount() {
		return this.lstNewsItems.size();
	}
	
	public static final long VERSION = 3;
	public static final long serialVersionUID = (7526472295622770000L + VERSION);
}